package com.jiang.android.pbutton;


import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorGroup;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Button;
import ohos.agp.components.Component;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.render.Canvas;
import ohos.agp.utils.Color;
import ohos.app.Context;

/**
 * Created by jiang on 2017/3/1.
 */

public class CProgressButton extends Button implements ProgressListener {

    private ShapeElement mBackground;
    private com.jiang.android.pbutton.CProgressDrawable mProgressDrawable;
    private int mWidth;
    private int mHeight;
    private STATE mState = STATE.NORMAL;
    private boolean morphingCircle; //变形成圆中
    private boolean morphingNormal; //变形成正常状态中
    private float mFromCornerRadius = 40;
    private float mToCornerRadius = 90;
    private long mDuration = 500;
    private int mProgress;
    private int mMaxProgress = 100;
    private int mStrokeColor;
    private int mStokeWidth = 0;
    private int mStokeWidthOut = 0;
    private static String[] statusString = new String[]{"download", "pause", "complete", "error", "delete"};
    private String resultString;


    public enum STATE {
        PROGRESS, NORMAL
    }

    private static final String TAG = "CProgressButton";


    public CProgressButton(Context context) {
        this(context, null);
    }

    public CProgressButton(Context context, AttrSet attrs) {
        this(context, attrs, null);
    }

    public CProgressButton(Context context, AttrSet attrs, String sttleName) {
        super(context, attrs, sttleName);


        mStrokeColor = com.jiang.android.pbutton.AttrUtils.getColorFromAttr(attrs, "color", -1);
        mBackground = (ShapeElement) com.jiang.android.pbutton.AttrUtils.getElementFromAttr(attrs,"drawable_xml",null);

        mStokeWidthOut = com.jiang.android.pbutton.AttrUtils.getDimensionFromAttr(attrs, "stroke_width", -1);
        mFromCornerRadius = com.jiang.android.pbutton.AttrUtils.getDimensionFromAttr(attrs, "radius", -1);


        if (mStrokeColor == -1) {
            mStrokeColor = Color.BLACK.getValue();
        }
        if (mBackground == null) {
            throw new NullPointerException("drawable_xml can not be null");
        }

        if (mStokeWidthOut == -1) {
            mStokeWidthOut = dip2px(getContext(), 1);
        }
        if (mFromCornerRadius == -1) {
            throw new NullPointerException("radius must can not be null");
        }
        mStokeWidth = mStokeWidthOut * 3;
        normal(0);

        setLayoutRefreshedListener(new LayoutRefreshedListener() {
            @Override
            public void onRefreshed(Component component) {
                mWidth = getWidth() - getPaddingLeft() - getPaddingRight();
                mHeight = getHeight() - getPaddingTop() - getPaddingRight();
                if (mState == STATE.NORMAL || (mState == STATE.PROGRESS && morphingCircle)) {
                    setBound(0);
                } else {
                    invalidate();
                }
            }
        });

        addDrawTask(new DrawTask() {
            @Override
            public void onDraw(Component component, Canvas canvas) {
                if (mState == STATE.NORMAL || (mState == STATE.PROGRESS && morphingCircle)) {
                    mBackground.drawToCanvas(canvas);
                } else if (mState == STATE.PROGRESS && !morphingCircle) {
                    if (mProgressDrawable == null) {
                        int offset = (mWidth - mHeight) / 2 + getPaddingLeft();
                        int size = mHeight;
                        mProgressDrawable = new com.jiang.android.pbutton.CProgressDrawable(getContext(), size, mStokeWidth, mStokeWidthOut, mStrokeColor);
                        int left = offset;
                        mProgressDrawable.setBounds(left, getPaddingTop(), left + mHeight, getPaddingTop() + mHeight);
                    }
                    float sweepAngle = (360f / mMaxProgress) * mProgress;
                    mProgressDrawable.setSweepAngle(sweepAngle);
                    mProgressDrawable.drawToCanvas(canvas);

                }
            }
        });
    }


    /**
     * order by yourself
     *
     * @param status
     */
    public static void initStatusString(String[] status) {
        if (status != null && status.length > 0) {
            statusString = status;
        }
    }


    public STATE getState() {
        return mState;
    }


    private void setState(STATE state, boolean anim) {
        if (state == mState) {
            if (state == STATE.NORMAL) {
                setText(resultString);
            }
            return;
        }
        if (getWidth() == 0 || morphingCircle || morphingNormal)
            return;
        this.mState = state;
        if (anim) {
            if (mState == STATE.PROGRESS) {
                morph2Circle();
            } else if (mState == STATE.NORMAL) {
                morph2Normal();
            }
        } else {
            morphingCircle = morphingNormal = false;
            if (mState == STATE.PROGRESS) {
                setText("");
            } else if (mState == STATE.NORMAL) {
                setText(resultString);
            }
            setBound(0);
        }

    }


    private void setBound(int padding) {
        if (mWidth == 0) {
            mWidth = getWidth() - getPaddingLeft() - getPaddingRight();
        }
        if (mHeight == 0) {
            mHeight = getHeight() - getPaddingTop() - getPaddingRight();
        }
        mBackground.setBounds(getPaddingLeft() + padding, getPaddingTop(), getPaddingLeft() + mWidth - padding, getPaddingTop() + mHeight);
        invalidate();

    }

    private void setProgress(int progress) {
        mProgress = progress;
        if (morphingCircle || morphingNormal)
            return;
        if (mState != STATE.PROGRESS) {
            mState = STATE.PROGRESS;
            setText("");
        }
        if (mProgress >= mMaxProgress) {
            mProgress = mMaxProgress;
        }
        if (mProgress <= 0) {
            mProgress = 0;
        }
        setBound(0);
        invalidate();

    }


    float cornerRadius;

    private void morph2Normal() {

        AnimatorValue cornerAnimation = new AnimatorValue();
        cornerAnimation.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() {
            @Override
            public void onUpdate(AnimatorValue animatorValue, float v) {
                cornerRadius = mToCornerRadius + (mFromCornerRadius - mToCornerRadius) * v;
                mBackground.setCornerRadius(cornerRadius);
            }
        });

        final int start = (mWidth - mHeight) / 2;

        AnimatorValue animator = new AnimatorValue();
        animator.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() {
            @Override
            public void onUpdate(AnimatorValue animatorValue, float v) {
                int value = (int) ((1 - v) * start);
                setBound(value);
            }
        });
        AnimatorGroup animatorSet = new AnimatorGroup();
        animatorSet.setDuration(mDuration);
        animatorSet.runParallel(animator, cornerAnimation);
        animatorSet.setStateChangedListener(new Animator.StateChangedListener() {
            @Override
            public void onStart(Animator animator) {
                morphingNormal = true;

            }

            @Override
            public void onStop(Animator animator) {

            }

            @Override
            public void onCancel(Animator animator) {
                morphingNormal = false;

            }

            @Override
            public void onEnd(Animator animator) {
                morphingNormal = false;
                setText(resultString);
            }

            @Override
            public void onPause(Animator animator) {

            }

            @Override
            public void onResume(Animator animator) {

            }


        });
        animatorSet.start();
    }


    private void morph2Circle() {

        AnimatorValue cornerAnimation = new AnimatorValue();
        cornerAnimation.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() {
            @Override
            public void onUpdate(AnimatorValue animatorValue, float v) {
                cornerRadius = mFromCornerRadius + (mToCornerRadius - mFromCornerRadius) * v;
                mBackground.setCornerRadius(cornerRadius);
            }
        });

        final int end = (mWidth - mHeight) / 2;

        AnimatorValue animator = new AnimatorValue();
        animator.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() {
            @Override
            public void onUpdate(AnimatorValue animatorValue, float v) {
                int value = (int) (v * end);
                setBound(value);
            }
        });


        AnimatorGroup animatorSet = new AnimatorGroup();
        animatorSet.setDuration(mDuration);
        animatorSet.runParallel(animator, cornerAnimation);
        animatorSet.setStateChangedListener(new Animator.StateChangedListener() {
            @Override
            public void onStart(Animator animator) {
                setText("");
                morphingCircle = true;
            }

            @Override
            public void onStop(Animator animator) {

            }

            @Override
            public void onCancel(Animator animator) {
                morphingCircle = false;
            }

            @Override
            public void onEnd(Animator animator) {
                setText("");
                morphingCircle = false;
            }

            @Override
            public void onPause(Animator animator) {

            }

            @Override
            public void onResume(Animator animator) {

            }

        });
        animatorSet.start();


    }

    private static int dip2px(Context context, float dpValue) {
        return (int) (context.getResourceManager().getDeviceCapability().screenDensity / 160 * dpValue);
    }


    @Override
    public void download(int progress) {
        setProgress(progress);
    }

    @Override
    public void normal(int status) {
        normal(status, true);
    }

    public void normal(int status, boolean anim) {
        resultString = statusString[status];
        setState(STATE.NORMAL, anim);
    }

    @Override
    public void startDownLoad() {
        resultString = "";
        setState(STATE.PROGRESS, true);
    }


}
